package com.bobo.nutzbook.module;

import java.util.Date;

import javax.servlet.http.HttpSession;

import org.nutz.Nutz;
import org.nutz.dao.Cnd;
import org.nutz.dao.QueryResult;
import org.nutz.dao.pager.Pager;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.Scope;
import org.nutz.mvc.annotation.At;
import org.nutz.mvc.annotation.Attr;
import org.nutz.mvc.annotation.By;
import org.nutz.mvc.annotation.Fail;
import org.nutz.mvc.annotation.Filters;
import org.nutz.mvc.annotation.Ok;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.filter.CheckSession;

import com.bobo.nutzbook.bean.User;
import com.bobo.nutzbook.bean.UserProfile;
import com.bobo.nutzbook.util.Toolkit;


@IocBean //声明为Ioc容器中的一个Bean
@At("/user") //整个模块的路径前缀
@Ok("json:{ignoreNull:true, locked:'password|salt'}") //忽略password和salt属性,忽略空属性的json输出
//上句翻译成java代码的话即Json.toJson(obj, new JsonFormat().setIgnoreNull(true).setLocked("password|salt"))
@Fail("http:500") //抛出异常的话,就走500页面
/**
 * CheckSession 是 Nutz.Mvc 为你内置的一个唯一的过滤器，它的构造函数需要两个参数：
 * 检查 session 的什么属性？
 * 如果不存在，重定向到哪里？
 */
@Filters(@By(type=CheckSession.class, args={"me", "/"})) //检查当前Session是否带me这个属性
public class UserModule extends BaseModule {

    @At
    public int count() { //统计用户数的方法,算是个测试点
        return dao.count(User.class);
    }

    @At
    @Filters //覆盖UserModule类的@Filter注解,因为登陆可不能要求是个已经登陆的Session
    public Object login(@Param("username")String name, @Param("password")String password, 
    					@Param("captcha") String captcha, 
    					@Attr(scope=Scope.SESSION, value="nutz_captcha") String _captcha, //@Attr注解,可以用于获取req或session的attr
    					HttpSession session) {
    	NutMap re = new NutMap();
    	//1.判断验证码
    	if (!Toolkit.checkCaptcha(_captcha, captcha))
    	{
    		return re.setv("ok", false).setv("msg", "验证码错误");
    	}
    	
    	//2.判断登录信息
        User user = dao.fetch(User.class, Cnd.where("name", "=", name).and("password", "=", password));
        if (user == null) {
        	return re.setv("ok", false).setv("msg", "用户名或密码错误");
        } else {
            session.setAttribute("me", user.getId());
            return re.setv("ok", true);
        }
    }

    @At
    @Ok(">>:/") //跟其他方法不同,这个方法完成后就跳转首页了
    /**
     * 注：">>:/" 等价于 "redirect:/"；  "->:/" 等价于"forward:/"
     * */
    public void logout(HttpSession session) {
        session.invalidate();
    }

    @At
    public Object add(@Param("..")User user) { //两个点号是按对象属性一一设置
        NutMap re = new NutMap();
        String msg = checkUser(user, true);
        if (msg != null){
            return re.setv("ok", false).setv("msg", msg);
        }
        user.setCreateTime(new Date());
        user.setUpdateTime(new Date());
        user = dao.insert(user);
        return re.setv("ok", true).setv("data", user);
    }

    @At
    public Object update(@Param("..")User user) {
        NutMap re = new NutMap();
        String msg = checkUser(user, false);
        if (msg != null){
            return re.setv("ok", false).setv("msg", msg);
        }
        user.setName(null);//不允许更新用户名
        user.setCreateTime(null);//也不允许更新创建时间
        user.setUpdateTime(new Date());//设置正确的更新时间
        dao.updateIgnoreNull(user);//真正更新的其实只有password和salt
        return re.setv("ok", true);
    }

    @At
    public Object delete(@Param("id")int id, @Attr("me")int me) {
        if (me == id) {
            return new NutMap().setv("ok", false).setv("msg", "不能删除当前用户!!");
        }
        dao.delete(User.class, id); //再严谨一些的话,需要判断是否为>0
        dao.clear(UserProfile.class, Cnd.where("userId", "=", me));
        return new NutMap().setv("ok", true);
    }

    @At
    @Ok("json") //该句等价于@Ok("json:nice")
    public Object query(@Param("name")String name, @Param("..")Pager pager) {
        Cnd cnd = Strings.isBlank(name)? null : Cnd.where("name", "like", "%"+name+"%");
        QueryResult qr = new QueryResult();
        qr.setList(dao.query(User.class, cnd, pager));
        pager.setRecordCount(dao.count(User.class, cnd));
        qr.setPager(pager);
        return qr; //默认分页是第1页,每页20条
    }

    @At("/list")
    @Ok("jsp:/jsp/user/list") //真实路径是/list.jsp
    /**
     * 注："jsp:/list"和"jsp:list"是不一样的。"jsp:/list"对应路径是"/list.jsp"，而"jsp:list"对应路径是"/WEB-INF/list.jsp"。
     * 例如：@Ok("jsp:abc.def")将对应/WEB-INF/abc/def.jsp
     *     @Ok("jsp:/abc/def")或@Ok("jsp:/abc/def.jsp")将对应/abc/def.jsp
     */
    public void index() {
    }

    protected String checkUser(User user, boolean create) {
        if (user == null) {
            return "空对象";
        }
        if (create) {
            if (Strings.isBlank(user.getName()) || Strings.isBlank(user.getPassword()))
                return "用户名/密码不能为空";
        } else {
            if (Strings.isBlank(user.getPassword()))
                return "密码不能为空";
        }
        String passwd = user.getPassword().trim();
        if (6 > passwd.length() || passwd.length() > 12) {
            return "密码长度错误";
        }
        user.setPassword(passwd);
        if (create) {
            int count = dao.count(User.class, Cnd.where("name", "=", user.getName()));
            if (count != 0) {
                return "用户名已经存在";
            }
        } else {
            if (user.getId() < 1) {
                return "用户Id非法";
            }
        }
        if (user.getName() != null)
            user.setName(user.getName().trim());
        return null;
    }
}
